<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"> <head>
<title>Writing a twistd Plugin</title>
</head>

<body>
<h1>Writing a twistd Plugin</h1>

<p>This document describes adding subcommands to
the <code>twistd</code> command, as a way to facilitate the deployment
of your applications. <em>(This feature was added in Twisted 2.5)</em></p>

<p>The target audience of this document are those that have developed
a Twisted application which needs a command line-based deployment
mechanism.</p>

<p>There are a few prerequisites to understanding this document:</p>
<ul>
  <li>A basic understanding of the Twisted Plugin System (i.e.,
      the <code class="API">twisted.plugin</code> module) is
      necessary, however, step-by-step instructions will be
      given. Reading <a href="plugin.xhtml">The Twisted Plugin
      System</a> is recommended, in particular the <q>Extending an
      Existing Program</q> section.</li>
  <li>The <a href="application.xhtml">Application</a> infrastructure
    is used in <code>twistd</code> plugins; in particular, you should
    know how to expose your program's functionality as a Service.</li>
  <li>In order to parse command line arguments, the <code>twistd</code> plugin
    mechanism relies
    on <code>twisted.python.usage</code>, which is documented
    in <a href="options.xhtml">Using usage.Options</a>.</li>
</ul>

<h2>Goals</h2>

<p>After reading this document, the reader should be able to expose
their Service-using application as a subcommand
of <code>twistd</code>, taking into consideration whatever was passed
on the command line.</p>

<h2>A note on .tap files</h2>

<p>Readers may be confused about a historical file type associated
with Twisted, the <code>.tap</code> file. This was a kind of file that
was generated by a program named <code>mktap</code> and
which <code>twistd</code> can read. <code>.tap</code> files are
deprecated; this document has nothing to do with them, although the
technology described herein is very closely related to the old
system. Existing plugins that were written for the mktap system are
compatible with this <code>twistd</code> plugin system; the following
commands,
</p>

<pre class="shell">
$ mktap [foo] [options...]
$ twistd -n -f [foo].tap
</pre>

<p>
are equivalent to the command:</p>

<pre class="shell">$ twistd -n [foo] [options...]</pre>

<h2>Alternatives to twistd plugins</h2>
<p>The major alternative to the twistd plugin mechanism is the <code>.tac</code>
file, which is a simple script to be used with the
twistd <code>-y/--python</code> parameter. The twistd plugin mechanism
exists to offer a more extensible command-line-driven interface to
your application. For more information on <code>.tac</code> files, see
the document <a href="application.xhtml">Using the Twisted Application
Framework</a>.</p>


<h2>Creating the plugin</h2>

<p>The following directory structure is assumed of your project:</p>

<ul>
  <li><strong>MyProject</strong> - Top level directory
    <ul>
      <li><strong>myproject</strong> - Python package
        <ul><li><strong>__init__.py</strong></li></ul>
      </li>
    </ul>
  </li>
</ul>

<p>
  During development of your project, Twisted plugins can be loaded
  from a special directory in your project, assuming your top level
  directory ends up in sys.path. Create a directory
  named <code>twisted</code> containing a directory
  named <code>plugins</code>, and add a file
  named <code>myproject_plugin.py</code> to it. This file will contain your
  plugin. Note that you should <em>not</em> add any __init__.py files
  to this directory structure, and the plugin file should <em>not</em>
  be named <code>myproject.py</code> (because that would conflict with
  your project's module name).
</p>

<p>
  In this file, define an object which <em>provides</em> the interfaces
  <code class="API">twisted.plugin.IPlugin</code>
  and <code
  class="API">twisted.application.service.IServiceMaker</code>.
</p>

<p>The <code>tapname</code> attribute of your IServiceMaker provider
will be used as the subcommand name in a command
like <code class="shell">twistd [subcommand] [args...]</code>, and
the <code>options</code> attribute (which should be
a <code class="API" base="twisted.python">usage.Options</code>
subclass) will be used to parse the given args.</p>

<pre class="python">
from zope.interface import implements

from twisted.python import usage
from twisted.plugin import IPlugin
from twisted.application.service import IServiceMaker
from twisted.application import internet

from myproject import MyFactory


class Options(usage.Options):
    optParameters = [["port", "p", 1235, "The port number to listen on."]]


class MyServiceMaker(object):
    implements(IServiceMaker, IPlugin)
    tapname = "myproject"
    description = "Run this! It'll make your dog happy."
    options = Options

    def makeService(self, options):
        """
        Construct a TCPServer from a factory defined in myproject.
        """
        return internet.TCPServer(int(options["port"]), MyFactory())


# Now construct an object which *provides* the relevant interfaces
# The name of this variable is irrelevant, as long as there is *some*
# name bound to a provider of IPlugin and IServiceMaker.

serviceMaker = MyServiceMaker()
</pre>

<p>
  Now running <code class="shell">twistd --help</code> should
  print <code>myproject</code> in the list of available subcommands,
  followed by the description that we specified in the
  plugin. <code class="shell">twistd -n myproject</code> would,
  assuming we defined a <code>MyFactory</code> factory
  inside <code>myproject</code>, start a listening server on port 1235
  with that factory.
</p>

<h2>Using cred with your TAP</h2>

<p>
  Twisted ships with a robust authentication framework to use with
  your application. If your server needs authentication functionality,
  and you haven't read about <a href="cred.xhtml">twisted.cred</a>
  yet, read up on it first.
</p>

<p>
  If you are building a twistd plugin and you want to support a wide
  variety of authentication patterns, Twisted provides an easy-to-use
  mixin for your Options subclass:
  <code class="API" base="twisted.cred">strcred.AuthOptionMixin</code>.
  The following code is an example of using this mixin:
</p>

<pre class="python">
from twisted.cred import credentials, portal, strcred
from twisted.python import usage
from twisted.plugin import IPlugin
from twisted.application.service import IServiceMaker
from myserver import myservice

class ServerOptions(usage.Options, strcred.AuthOptionMixin):
    # This part is optional; it tells AuthOptionMixin what
    # kinds of credential interfaces the user can give us.
    supportedInterfaces = (credentials.IUsernamePassword,)

    optParameters = [
        ["port", "p", 1234, "Server port number"],
        ["host", "h", "localhost", "Server hostname"]]

class MyServerServiceMaker(object):
    implements(IServiceMaker, IPlugin)
    tapname = "myserver"
    description = "This server does nothing productive."
    options = ServerOptions

    def makeService(self, options):
        """Construct a service object."""
        # The realm is a custom object that your server defines.
        realm = myservice.MyServerRealm(options["host"])

        # The portal is something Cred can provide, as long as
        # you have a list of checkers that you'll support. This
        # list is provided my AuthOptionMixin.
        portal = portal.Portal(realm, options["credCheckers"])

        # OR, if you know you might get multiple interfaces, and
        # only want to give your application one of them, you
        # also have that option with AuthOptionMixin:
        interface = credentials.IUsernamePassword
        portal = portal.Portal(realm, options["credInterfaces"][interface])

        # The protocol factory is, like the realm, something you implement.
        factory = myservice.ServerFactory(realm, portal)

        # Finally, return a service that will listen for connections.
        return internet.TCPServer(int(options["port"]), factory)


# As in our example above, we have to construct an object that
# provides the IPlugin and IServiceMaker interfaces.

serviceMaker = MyServerServiceMaker()
</pre>

<p>
  Now that you have your TAP configured to support any authentication
  we can throw at it, you're ready to use it. Here is an example of
  starting your server using the /etc/passwd file for
  authentication. (Clearly, this won't work on servers with shadow
  passwords.)
</p>

<pre class="shell">
$ twistd myserver --auth passwd:/etc/passwd
</pre>

<p>
  For a full list of cred plugins supported, see <code
  class="API">twisted.plugins</code>, or use the command-line help:
</p>

<pre class="shell">
$ twistd myserver --help-auth
$ twistd myserver --help-auth-type passwd
</pre>

<h2>Conclusion</h2>

<p>You should now be able to</p>
<ul>
  <li>Create a twistd plugin</li>
  <li>Incorporate authentication into your plugin</li>
  <li>Use it from your development environment</li>
  <li>Install it correctly and use it in deployment</li>
</ul>


</body> </html>
